/*! 
 * Header file for the collision algorithm manager.
 *
 * \author Devis Rossini
 * \date 20 April 2012
 */
#ifndef PHXCOLLISIONALGORITHM_MANAGER_H_INCLUDE_GUARD
#define PHXCOLLISIONALGORITHM_MANAGER_H_INCLUDE_GUARD

#include "PhxCollisionAlgorithm.h"

#include "PhxCollisionPrimitive.h"
#include "PhxCollisionPrimitiveDescriptor.h"

#include "PhxCollisionData.h"

#include <map>
#include <utility>

namespace phx
{
	/*! 
	 * Key type used for register algorithms.
	 */
 	class AlgorithmKey
	{
	private:

		typedef std::pair<ShapeTypes, ShapeTypes> KeyType;

	public:

		AlgorithmKey() { }

		AlgorithmKey(const ShapeTypes iType1, const ShapeTypes iType2)
			: mKey(std::make_pair(iType1, iType2)) { }

		inline const ShapeTypes GetType1() const
		{
			return mKey.first;
		}

		inline const ShapeTypes GetType2() const 
		{
			return mKey.second;
		}

		inline const KeyType& GetPair() const 
		{
			return mKey;
		}

		inline void SetType1(const ShapeTypes iType) 
		{
			mKey.first = iType;
		}

		inline void SetType2(const ShapeTypes iType) 
		{
			mKey.second = iType;
		}

		bool IsEqual(const AlgorithmKey& iKey) const
		{
			if (mKey.first == iKey.GetType1() && 
					mKey.second == iKey.GetType2()) 
			{
				return true;
			}

			if (mKey.first == iKey.GetType2() &&
					mKey.second == iKey.GetType1())
			{
				return true;
			}

			return false;
		}

		inline bool operator<(const AlgorithmKey& iKey) const 
		{
			return (mKey < iKey.GetPair());
		}

		inline bool operator>(const AlgorithmKey& iKey) const 
		{
			return (mKey > iKey.GetPair());
		}

		inline bool operator==(const AlgorithmKey& iKey) const 
		{
			return (mKey == iKey.GetPair());
		}

		inline bool operator!=(const AlgorithmKey& iKey) const 
		{
			return (mKey != iKey.GetPair());
		}

		inline bool LessThan(const AlgorithmKey& iKey) const 
		{
			return (mKey < iKey.GetPair());
		}

		inline bool GreaterThan(const AlgorithmKey& iKey) const 
		{
			return (mKey > iKey.GetPair());
		}

		inline bool EqualsThan(const AlgorithmKey& iKey) const 
		{
			return (mKey == iKey.GetPair());
		}

	private:

		KeyType mKey;
	};

	/*!
	 * Generic collision algorithm.
	 */ 
	typedef unsigned(*Algorithm)(const CollisionPrimitive*, const CollisionPrimitive*, CollisionData*);

	class CollisionAlgorithmManager
	{
	public:

		CollisionAlgorithmManager() { }

		/*!
		 * Register a new collision algorithm.
		 */ 
		inline void RegisterAlgorithm(const ShapeTypes iType1, const ShapeTypes iType2, Algorithm iAlgorithm)
		{
			AlgorithmKey key(iType1, iType2);

			mAlgorithmMap[key] = iAlgorithm;
		}

		/*!
		 * Return a collision algorithm in order to calculate a collision between two specified shape types.
		 */ 
		inline Algorithm GetAlgorithm(const ShapeTypes iType1, const ShapeTypes iType2)
		{
			AlgorithmKey key(iType1, iType2);

			return mAlgorithmMap[key];
		}

	private:

		std::map<AlgorithmKey, Algorithm> mAlgorithmMap;
	};
}

#endif // PHXCOLLISIONALGORITHM_MANAGER_H_INCLUDE_GUARD